﻿#region License

// // -------------------------------------------------------------------------------------
// // This information refers to PerformanceEvent.cs
// // 
// // Copyright 2012 ELEN7046 Group 2
// // 
// // Last Modified on: 2012-06-10
// // 
// // Contributors:
// // 
// // Amith Sewnarain
// // Elmar Vosloo
// // Jason Thorne
// // Satish Jewan
// // 
// // Wits University 
// // School of Electrical & Information Engineering
// // Software Engineering Tools and Techniques
// // 
// // -------------------------------------------------------------------------------------
// // 
// // This file (PerformanceEvent.cs) is part of the DishDash Event Visualization System.
// // 
// // DishDash is free software: you can redistribute it and/or modify
// // it under the terms of the GNU General Public License as published by
// // the Free Software Foundation, either version 3 of the License, or
// // (at your option) any later version.
// // 
// // DishDash is distributed in the hope that it will be useful,
// // but WITHOUT ANY WARRANTY; without even the implied warranty of
// // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// // GNU General Public License for more details.
// // 
// // You should have received a copy of the GNU General Public License
// // along with DishDash.  
// // If not, see <http://www.gnu.org/licenses/>.
// // -------------------------------------------------------------------------------------

#endregion

#region Using Directives

using System;
using System.Collections.Generic;
using System.Text;

#endregion

namespace DishDash.Common
{
    public class PerformanceEvent
    {
        private Dictionary<string, string> contextValues;

        /// <summary>
        /// Initializes a new instance of the <see cref="PerformanceEvent"/> class.
        /// </summary>
        public PerformanceEvent()
        {
            contextValues = new Dictionary<string, string>();
        }

        /// <summary>
        /// Gets or sets the category.
        /// </summary>
        /// <value>
        /// The category.
        /// </value>
        public string Category { get; set; }
        /// <summary>
        /// Gets or sets the time stamp.
        /// </summary>
        /// <value>
        /// The time stamp.
        /// </value>
        public long TimeStamp { get; set; }
        /// <summary>
        /// Gets or sets the value.
        /// </summary>
        /// <value>
        /// The value.
        /// </value>
        public long Value { get; set; }

        /// <summary>
        /// Gets the context values.
        /// </summary>
        public Dictionary<string, string> ContextValues
        {
            get { return contextValues; }
            private set { this.contextValues = value; }
        }

        /// <summary>
        /// Gets or sets the precisions.
        /// </summary>
        /// <value>
        /// The precisions.
        /// </value>
        public Precision Precisions
        {
            get { return new Precision(this.TimeStamp); }
            set
            {
                //ignore
            }
        }

        /// <summary>
        /// Adds the context value.
        /// </summary>
        /// <param name="contextKey">The context key.</param>
        /// <param name="contextValue">The context value.</param>
        /// <returns></returns>
        public PerformanceEvent AddContextValue(string contextKey, string contextValue)
        {
            if (!this.contextValues.ContainsKey(contextKey))
            {
                this.contextValues.Add(contextKey, contextValue);
            }
            else
            {
                this.contextValues[contextKey] = contextValue;
            }

            return this;
        }

        /// <summary>
        /// Converts the specified string to a performance event.
        /// </summary>
        /// <param name="data">The data.</param>
        /// <returns></returns>
        public static PerformanceEvent FromString(string data)
        {
            if (string.IsNullOrWhiteSpace(data))
            {
                throw new ArgumentException("Input string is in the incorrect format.");
            }

            var performanceEvent = new PerformanceEvent();

            var performanceData = data.Split(' ');

            if (performanceData.Length < 4)
            {
                throw new ArgumentException("Input string is in the incorrect format.");
            }

            performanceEvent.Category = performanceData[0];

            long timeStamp = 0;

            if (!long.TryParse(performanceData[1], out timeStamp))
            {
                throw new ArgumentException("Input string is in the incorrect format.");
            }

            performanceEvent.TimeStamp = timeStamp;

            long perfValue = 0;

            if (!long.TryParse(performanceData[2], out perfValue))
            {
                throw new ArgumentException("Input string is in the incorrect format.");
            }

            performanceEvent.Value = perfValue;

            for (int i = 3; i < performanceData.Length; i++)
            {
                var contextItem = performanceData[i].Split('=');
                if (contextItem.Length != 2)
                {
                    throw new ArgumentException("Input string is in the incorrect format.");
                }

                performanceEvent.AddContextValue(contextItem[0], contextItem[1]);
            }

            return performanceEvent;
        }

        /// <summary>
        /// Returns a <see cref="System.String"/> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String"/> that represents this instance.
        /// </returns>
        public override string ToString()
        {
            var builder = new StringBuilder();

            builder.Append(this.Category);
            builder.Append(" ");
            builder.Append(this.TimeStamp);
            builder.Append(" ");
            builder.Append(this.Value);

            foreach (var key in contextValues.Keys)
            {
                builder.Append(" ");
                builder.Append(key);
                builder.Append("=");
                builder.Append(contextValues[key]);
            }

            return builder.ToString();
        }

        #region Nested type: Precision

        /// <summary>
        /// 
        /// </summary>
        public class Precision
        {
            private readonly long timestamp;

            /// <summary>
            /// Initializes a new instance of the <see cref="Precision"/> class.
            /// </summary>
            /// <param name="timestamp">The timestamp.</param>
            public Precision(long timestamp)
            {
                this.timestamp = timestamp;
            }

            /// <summary>
            /// Gets or sets the second.
            /// </summary>
            /// <value>
            /// The second.
            /// </value>
            public long Second
            {
                get { return Convert.ToInt64(new TimeSpan(timestamp).TotalSeconds); }
                set { }
            }

            /// <summary>
            /// Gets or sets the minute.
            /// </summary>
            /// <value>
            /// The minute.
            /// </value>
            public long Minute
            {
                get { return Convert.ToInt64(new TimeSpan(timestamp).TotalMinutes); }
                set { }
            }

            /// <summary>
            /// Gets or sets the hour.
            /// </summary>
            /// <value>
            /// The hour.
            /// </value>
            public long Hour
            {
                get { return Convert.ToInt64(new TimeSpan(timestamp).TotalHours); }
                set { }
            }

            /// <summary>
            /// Gets or sets the day.
            /// </summary>
            /// <value>
            /// The day.
            /// </value>
            public long Day
            {
                get { return Convert.ToInt64(new TimeSpan(timestamp).TotalDays); }
                set { }
            }
        }

        #endregion
    }
}